package com.jfinal.ext.ueditor.service;

import com.jfinal.ext.ueditor.config.CatchImageConfig;
import com.jfinal.ext.ueditor.result.CatchImageResult;
import com.jfinal.ext.ueditor.storage.IStorageManager;
import com.jfinal.ext.ueditor.storage.StorageResult;
import com.jfinal.ext.util.FormatUtil;
import com.jfinal.ext.util.rand.MyUuidUtil;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.net.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 图片抓取器
 * @author Timor
 * @version 1.0
 * @date 2023/03/15 14:49:56
 */
public class ImageHunter {
    private final IStorageManager storageManager;

    public ImageHunter(@NotNull IStorageManager storageManager) {
        this.storageManager = storageManager;
    }

    public CatchImageResult catchImage(
            @NotNull String source, @NotNull CatchImageConfig config) {
        try {
            final URL url = new URL(source);

            if (!validHost(url.getHost(), config.getLocalDomain())) {
                return new CatchImageResult("被阻止的远程主机");
            }


            final HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            connection.setInstanceFollowRedirects(true);
            connection.setUseCaches(true);

            if (!validContentState(connection.getResponseCode())) {
                return new CatchImageResult("远程连接出错");
            }


            // 图片类型校验
            final String contentType = Optional.ofNullable(connection.getContentType()).orElse("unknown/unknown");
            final String extension = contentType.substring(contentType.indexOf("/") + 1);
            final String type = "." + extension;

            if (config.getAllowFiles().stream().noneMatch(type::equals)) {
                return new CatchImageResult("不支持的文件类型");
            }


            // 图片大小校验
            final int contentLength = connection.getContentLength();

            if (contentLength > config.getMaxSize()) {
                return new CatchImageResult("图片大小超出限制");
            }

            if (contentLength <= 0) {
                return new CatchImageResult("图片为空图片");
            }


            final String path = FormatUtil.parse(config.getPathFormat(), Map.of(
                    FormatUtil.FILE_NAME, MyUuidUtil.get(),
                    FormatUtil.FILE_TYPE, extension,
                    FormatUtil.PREFIX, "",
                    FormatUtil.SUFFIX, ""));

            final StorageResult result = storageManager.saveFileByInputStream(
                    connection.getInputStream(), contentLength, path);

            if (result.isFail()) {
                return new CatchImageResult("抓取图片失败！");
            }

            return new CatchImageResult(result.getUrl(), source);
        } catch (MalformedURLException e) {
            return new CatchImageResult("无效链接：" + source);
        } catch (IOException e) {
            return new CatchImageResult("抓取远程图片失败");
        }
    }

    private boolean validHost(String hostname, List<String> filters) {
        try {
            final InetAddress ip = InetAddress.getByName(hostname);

            if (ip.isSiteLocalAddress()) {
                return false;
            }
        } catch (UnknownHostException e) {
            return false;
        }

        return !filters.contains(hostname);
    }

    private boolean validContentState(int code) {
        return HttpURLConnection.HTTP_OK == code;
    }

}
